#include <mutex>

template<class T>
struct DFDef
{
	void operator()(T*& ptr)
	{
		if (ptr)
		{
			delete ptr;
			ptr = nullptr;
		}
	}
};


template<class T>
struct Free
{
	void operator()(T*& ptr)
	{
		if (ptr)
		{
			free(ptr);
			ptr = nullptr;
		}
	}
};

struct FClose
{
	void operator()(FILE* pf)
	{
		if (pf)
		{
			fclose(pf);
			pf = nullptr;
		}
	}
};

namespace dun
{
	template<class T, class DF = DFDef<T>>
	class shared_ptr
	{
	public:
		// RAII
		shared_ptr(T* ptr = nullptr)
			: _ptr(ptr)
			, _pRefCount(nullptr)
			, _pMutex(nullptr)
		{
			if (_ptr)
			{
				_pRefCount = new int(1);
				_pMutex = new mutex;
			}
		}

		~shared_ptr()
		{
			Release();
		}

		////////////////////////////////
		// 具有指针类似的行为
		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		//////////////////////////////////
		//
		shared_ptr(const shared_ptr<T>& sp)
			: _ptr(sp._ptr)
			, _pRefCount(sp._pRefCount)
			, _pMutex(sp._pMutex)
		{
			AddRef();
		}

		shared_ptr<T, DF>& operator=(const shared_ptr<T, DF>& sp)
		{
			// sp1
			// shared_ptr<int> sp2(sp1);
			// if(this == &sp)

			// sp2 = sp1
			if (_ptr != sp._ptr)
			{
				Release();

				// this和sp共享资源
				_ptr = sp._ptr;
				_pRefCount = sp._pRefCount;
				_pMutex = sp._pMutex;
				AddRef();
			}

			return *this;
		}

		size_t use_count()const
		{
			return *_pRefCount;
		}

		T* Get()
		{
			return _ptr;
		}

	private:
		void AddRef()
		{
			if (_pRefCount)
			{
				_pMutex->lock();
				++(*_pRefCount);
				_pMutex->unlock();
			}
		}

		int SubRef()
		{
			_pMutex->lock();
			--*_pRefCount;
			_pMutex->unlock();

			return *_pRefCount;
		}

		void Release()
		{
			if (_ptr && 0 == SubRef())
			{
				DF()(_ptr);
				delete _pRefCount;
				_ptr = nullptr;
				_pRefCount = nullptr;
				delete _pMutex;
			}
			
		}
	private:
		T* _ptr;
		int* _pRefCount;
		mutex* _pMutex;  // 保证shared_ptr内置实现安全性
		                 // 无法保证对管理资源的安全性
	};
}


void TestBitSharedPtr1()
{
	dun::shared_ptr<int> sp1(new int);
	*sp1 = 10;
	cout << sp1.use_count() << endl;

	dun::shared_ptr<int> sp2(sp1);
	*sp1 = 100;
	*sp2 = 200;

	cout << sp1.use_count() << endl;
	cout << sp2.use_count() << endl;

	dun::shared_ptr<int> sp3(new int);
	dun::shared_ptr<int> sp4(sp3);
	dun::shared_ptr<int> sp5(sp3);

	sp2 = sp2;
	sp3 = sp2;
	sp3 = sp2;
	sp4 = sp2;
	sp5 = sp2;
}
//多线程测试
class Date
{
public:
    Date(int year = 0, int month = 0, int day = 0)
            : _year(year)
            , _month(month)
            , _day(day)
    {}

public:
    int _year;
    int _month;
    int _day;
};
void TestSharedPtrThread(dun::shared_ptr<Date>& sp1,int n){
    for(int i=0;i<n;i++){
        dun::shared_ptr<Date>sp(sp1);
        sp->_day++;
        sp->_month++;
        sp->_year++;
    }
}
#include <thread>
void TestBitSharedPtr2()
{
    dun::shared_ptr<Date> sp1(new Date());

    thread t1;  // 单纯创建了一个对象，该对象没有与任何线程关联
    thread t2(TestSharedPtrThread, sp1, 100000);
    thread t3(TestSharedPtrThread, sp1, 100000);

    t2.join();
    t3.join();

    cout << sp1->_year << endl;
    cout << sp1->_month << endl;
    cout << sp1->_day << endl;
}
